/***************************************************************************
 *   Copyright (C) 2008 by Ivan Blagoev Topolsky   *
 *   ivan.topolsky@genebio.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 3 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef XENO_MERLINARTHUR_H
#define XENO_MERLINARTHUR_H

#include <iostream>
#include <string>

// Captain-bol
#include <runlcmsms.h>
// Xeno-bol
#include "xeno.h"

// OLE/COM support
#include "disphelper.h"

#include "filterparse.h"


#define DEFAULT_RUNNAME_TEMPLATE "#SampleId #SampleName"

namespace xeno {
namespace merlin {


using namespace std;	// STL
using namespace bol;	// Captain bol

	/*
	 * ENUMs from XDK
	 */
	typedef enum {
		XNo_Device = 0xffffffff,
		XMS_Device = 0,
		XMS_Analog_Device = 1,
		XAnalog_Device = 2,
		XPDA_Device = 3,
		XUV_Device = 4
	} XDetectorTypes;
	
	typedef enum {
		XSampleUnknown = 0,
		XSampleBlank = 1,
		XSampleQC = 2,
		XSampleStdClear = 3,
		XSampleStdUpdate = 4,
		XSampleStdBracket = 5,
		XSampleStdBracketStart = 6,
		XSampleStdBracketEnd = 7,
		XSampleProgram = 8,
		XSampleNumbersOfDifferentTypes = 9
	} XSampleTypes;
	
	typedef enum {
		XBarcodeNoRead = 0,
		XBarcodeRead = 1,
		XBarcodeUnreadable = 2,
		XBarcodeError = 3
	} XBarcodeStatus;
	
	typedef enum {
		XUnitsMMU = 0,
		XUnitsPPM = 1,
		XUnitsAMU = 2
	} XToleranceUnits;
	
	typedef enum {
		XSpectrumProfile = 0,
		XSpectrumCentroid = 1
	} XSpectrumTypes;
	
	static struct XDKNAMES {
		public:
			map<XDetectorTypes,string> XDetectors;
			map<XSampleTypes,string> SampleTypes;
			XDKNAMES();
	} XDKNames;




/**
	This class is used to package together the different phases in reading a Raw file
	together with the data which is passed around.

	It doesn't actually need to be an object, it's just better packaged like this.

	@author Ivan Blagoev Topolsky <ivan.topolsky@genebio.com>
*/
class arthur{
	/*
	 * Global data
	 */

public:
	// data
	RunLcmsms *run; // Run that we are building
	
	// parameters
	bool Centroiding;

	static const string default_runname_template;
private:
	// data that gets passed around between steps
	CDispPtr raw;	// base OLECOM object used to interface the object
	CDispPtr rawnfo;	// holds information about file used in 'init' and 'samplelist'
	CDispPtr detect;	// data obtained by a MS machin. used by dosample (and also by dospectra_all to get filters)
	int numdetect;	// number of detectors
	int numfilter;	//
	vector<FilterParse * >	filters;	// stores all the filters' Text, parsed into a use full format
	
	// temporary data built to quickly find needed thing
	vector<unsigned short>	parentmap;
	vector<SpectrumLcms*>	parentsp1;
	vector<SpectrumLcmsms*>	parentsp2;
	vector<bool>	extractmap;

	/// sample properties
	static const wchar_t
		*fields_str[],	// String properties. Return BSTR
		*fields_dbl[],	// Return double
		*fields_num[],	// return some integers
		*fields_enu[];
		
	/// We will use string substitution de replace a template with "#Fields" 
	static inline void printnfoname(const wchar_t **f, ostream& out = cout) {
		for(;*f;f++) {
#if defined(__GNUC__) && (__GNUC__<4)
		// MinGW is based on an older version of GCC which picks up the wrong operator if not forced :
		::operator<< ((ostream&)(out << "#"),*f) << ", ";
#else
			out << "#" << (const wchar_t *)(*f) << ", ";
#endif	
		}
	}
	static inline string& nfo(string& name, const string& label, const string& val);
	static inline string& nfo(string& name, const wchar_t *label, const string&  val);
	/// This template is used to process all Sample properties which return a given TYPE
	template <typename TYPE> static inline void shownfo(string *name, const wchar_t *fmt, IDispatch *sample, const wchar_t **f, map<TYPE,string>*mptr = NULL);

public:
	arthur() : Centroiding(false), filters(0), parentmap(0), parentsp1(0), parentsp2(0), extractmap(0), numdetect(0), run(NULL) { }
	~arthur() { }
	
	RunLcmsms *getRun() { return run; }
	RunLcmsms *setRun(RunLcmsms *ptr) { return run = ptr; }

	/**
	 * list all "#Fields" that can be used in a runname template
	 */
	static void printhelp(ostream& out = cout) {
		printnfoname(fields_str, out);
		printnfoname(fields_dbl, out);
		printnfoname(fields_num, out);
		printnfoname(fields_enu, out);
		out << "#User1, #User2, #User3, #User4 and #User5" << endl;
	}

	/**
	 * decoding steps :
	 */
	void initfile(const char *ifname, RunLcmsms *ptr = NULL);
	void samplelist(const string* nametmpl = &default_runname_template);
	
	void dosample(const bool allatonce = false, const bool skipms1 = false, const bool skipms2 = false, const bool dropms1 = false, const bool dropms2 = false, ExtractList *reflist = NULL);
	
	typedef void (arthur::*EFFECTOR_FUNC_PTR) (const int d, const int f, CDispPtr spect, const unsigned short scannum, const double retentiontime, const bool skip, bool docentroid);

	void dospectra(const EFFECTOR_FUNC_PTR effector, const int d, const int f, const bool skip = false);
	void dospectra_all(const int d, const bool skipms1 = false, const bool skipms2 = false, const bool dropms1 = false, const bool dropms2 = false);

	void do_single_spectrum_ms1(const int d, const int f, CDispPtr spect, const unsigned short scannum, const double retentiontime, const bool skip = false, bool docentroid = false);
	void do_single_spectrum_ms2(const int d, const int f, CDispPtr spect, const unsigned short scannum, const double retentiontime, const bool skip = false, bool docentroid = false);

	
	void getdata(Spectrum< PeakIntensity* > *sp, CDispPtr spect) throw(string);
	void buildptr();
	
	void initextract_map(unsigned short detector, ExtractList *ptr);
};




} // merlin
} // xeno

#endif
